package core

import (
	"encoding/base64"
	"encoding/json"
	"fmt"
	"io"
	"net/url"
	"os"
	"path/filepath"
	"regexp"
	"res-downloader/core/shared"
	"strconv"
	"strings"
	"sync"
)

type WxFileDecodeResult struct {
	SavePath string
	Message  string
}

type Resource struct {
	mediaMark  sync.Map
	resType    map[string]bool
	resTypeMux sync.RWMutex
	// 添加全局并发下载数控制
	activeDownloads int
	downloadMutex   sync.Mutex
	downloadSemaphore chan struct{}
}

func initResource() *Resource {
	if resourceOnce == nil {
		resourceOnce = &Resource{}
		resourceOnce.resType = resourceOnce.buildResType(globalConfig.MimeMap)
		// 初始化下载信号量
		resourceOnce.downloadSemaphore = make(chan struct{}, globalConfig.DownNumber)
	}
	return resourceOnce
}

func (r *Resource) buildResType(mime map[string]MimeInfo) map[string]bool {
	t := map[string]bool{
		"all": true,
	}

	for _, item := range mime {
		if _, ok := t[item.Type]; !ok {
			t[item.Type] = true
		}
	}

	return t
}

func (r *Resource) mediaIsMarked(key string) bool {
	_, loaded := r.mediaMark.Load(key)
	return loaded
}

func (r *Resource) markMedia(key string) {
	r.mediaMark.Store(key, true)
}

func (r *Resource) getResType(key string) (bool, bool) {
	r.resTypeMux.RLock()
	value, ok := r.resType[key]
	r.resTypeMux.RUnlock()
	return value, ok
}

func (r *Resource) setResType(n []string) {
	r.resTypeMux.Lock()
	for key := range r.resType {
		r.resType[key] = false
	}

	for _, value := range n {
		if _, ok := r.resType[value]; ok {
			r.resType[value] = true
		}
	}
	r.resTypeMux.Unlock()
}

func (r *Resource) clear() {
	r.mediaMark.Clear()
}

func (r *Resource) delete(sign string) {
	r.mediaMark.Delete(sign)
}

func (r *Resource) updateDownloadSemaphore() {
	r.downloadMutex.Lock()
	defer r.downloadMutex.Unlock()
	
	// 创建新的信号量
	newSemaphore := make(chan struct{}, globalConfig.DownNumber)
	
	// 如果有旧的信号量，关闭它
	if r.downloadSemaphore != nil {
		close(r.downloadSemaphore)
	}
	
	r.downloadSemaphore = newSemaphore
	fmt.Printf("[DEBUG] 更新下载信号量大小 - 新的并发数: %d\n", globalConfig.DownNumber)
}

func (r *Resource) getActiveDownloads() int {
	r.downloadMutex.Lock()
	defer r.downloadMutex.Unlock()
	return r.activeDownloads
}

func (r *Resource) resetActiveDownloads() {
	r.downloadMutex.Lock()
	defer r.downloadMutex.Unlock()
	
	if r.activeDownloads < 0 {
		fmt.Printf("[DEBUG] 重置活跃下载数 - 从 %d 重置为 0\n", r.activeDownloads)
		r.activeDownloads = 0
	}
}

func (r *Resource) download(mediaInfo MediaInfo, decodeStr string) {
	if globalConfig.SaveDirectory == "" {
		return
	}
	
	// 添加关键打印：显示当前下载配置
	fmt.Printf("[DEBUG] 开始下载任务 - ID: %s, URL: %s, 当前配置 DownNumber: %d, TaskNumber: %d\n", 
		mediaInfo.Id, mediaInfo.Url, globalConfig.DownNumber, globalConfig.TaskNumber)
	
	// 使用信号量控制并发下载数
	select {
	case r.downloadSemaphore <- struct{}{}:
		// 获取到信号量，可以开始下载
		r.downloadMutex.Lock()
		r.activeDownloads++
		currentActive := r.activeDownloads
		r.downloadMutex.Unlock()
		
		fmt.Printf("[DEBUG] 获取下载信号量 - ID: %s, 当前活跃下载数: %d\n", mediaInfo.Id, currentActive)
		
		go func(mediaInfo MediaInfo) {
			defer func() {
				// 释放信号量
				<-r.downloadSemaphore
				r.downloadMutex.Lock()
				r.activeDownloads--
				if r.activeDownloads < 0 {
					r.activeDownloads = 0
				}
				currentActive := r.activeDownloads
				r.downloadMutex.Unlock()
				fmt.Printf("[DEBUG] 释放下载信号量 - ID: %s, 当前活跃下载数: %d\n", mediaInfo.Id, currentActive)
			}()
			
			rawUrl := mediaInfo.Url
			fileName := shared.Md5(rawUrl)
			if mediaInfo.Description != "" {
				fileName = regexp.MustCompile(`[^\w\p{Han}]`).ReplaceAllString(mediaInfo.Description, "")
				fileLen := globalConfig.FilenameLen
				if fileLen <= 0 {
					fileLen = 10
				}

				runes := []rune(fileName)
				if len(runes) > fileLen {
					fileName = string(runes[:fileLen])
				}
			}

			if globalConfig.FilenameTime {
				mediaInfo.SavePath = filepath.Join(globalConfig.SaveDirectory, fileName+"_"+shared.GetCurrentDateTimeFormatted()+mediaInfo.Suffix)
			} else {
				mediaInfo.SavePath = filepath.Join(globalConfig.SaveDirectory, fileName+mediaInfo.Suffix)
			}

			if strings.Contains(rawUrl, "qq.com") {
				if globalConfig.Quality == 1 &&
					strings.Contains(rawUrl, "encfilekey=") &&
					strings.Contains(rawUrl, "token=") {
					parseUrl, err := url.Parse(rawUrl)
					queryParams := parseUrl.Query()
					if err == nil && queryParams.Has("encfilekey") && queryParams.Has("token") {
						rawUrl = parseUrl.Scheme + "://" + parseUrl.Host + "/" + parseUrl.Path +
							"?encfilekey=" + queryParams.Get("encfilekey") +
							"&token=" + queryParams.Get("token")
					}
				} else if globalConfig.Quality > 1 && mediaInfo.OtherData["wx_file_formats"] != "" {
					format := strings.Split(mediaInfo.OtherData["wx_file_formats"], "#")
					qualityMap := []string{
						format[0],
						format[len(format)/2],
						format[len(format)-1],
					}
					rawUrl += "&X-snsvideoflag=" + qualityMap[globalConfig.Quality-2]
				}
			}

			headers, _ := r.parseHeaders(mediaInfo)

			// 添加关键打印：显示下载器配置
			fmt.Printf("[DEBUG] 创建下载器 - ID: %s, TaskNumber: %d, 文件大小: %s\n", 
				mediaInfo.Id, globalConfig.TaskNumber, mediaInfo.Size)

			downloader := NewFileDownloader(rawUrl, mediaInfo.SavePath, globalConfig.TaskNumber, headers)
			downloader.progressCallback = func(totalDownloaded, totalSize float64, taskID int, taskProgress float64) {
				// 添加关键打印：显示进度更新频率
				fmt.Printf("[DEBUG] 进度更新 - ID: %s, TaskID: %d, 总进度: %.2f%%, 任务进度: %.2f%%, 已下载: %.0f/%.0f\n", 
					mediaInfo.Id, taskID, (totalDownloaded/totalSize)*100, taskProgress, totalDownloaded, totalSize)
				
				// 当下载进度达到100%时，发送完成状态
				if totalDownloaded >= totalSize && totalSize > 0 {
					// 如果文件需要解密，先不发送完成状态，等解密完成后再发送
					if decodeStr == "" {
						fmt.Printf("[DEBUG] 下载完成 - ID: %s\n", mediaInfo.Id)
						r.progressEventsEmit(mediaInfo, mediaInfo.SavePath, shared.DownloadStatusDone)
					}
				} else {
					r.progressEventsEmit(mediaInfo, strconv.Itoa(int(totalDownloaded*100/totalSize))+"%", shared.DownloadStatusRunning)
				}
			}
			err := downloader.Start()
			if err != nil {
				fmt.Printf("[DEBUG] 下载失败 - ID: %s, 错误: %v\n", mediaInfo.Id, err)
				r.progressEventsEmit(mediaInfo, err.Error())
				return
			}
			if decodeStr != "" {
				r.progressEventsEmit(mediaInfo, "decrypting in progress", shared.DownloadStatusRunning)
				if err := r.decodeWxFile(mediaInfo.SavePath, decodeStr); err != nil {
					r.progressEventsEmit(mediaInfo, "decryption error: "+err.Error())
					return
				}
				// 解密后更新保存路径为解密后的文件路径
				mediaInfo.SavePath = strings.ReplaceAll(mediaInfo.SavePath, ".mp4", "_decrypt.mp4")
			}
			// 确保最终发送完成状态（如果没有在progressCallback中发送）
			fmt.Printf("[DEBUG] 最终完成 - ID: %s, 保存路径: %s\n", mediaInfo.Id, mediaInfo.SavePath)
			r.progressEventsEmit(mediaInfo, mediaInfo.SavePath, shared.DownloadStatusDone)
		}(mediaInfo)
		
	default:
		// 信号量已满，拒绝下载请求，但返回就绪状态而不是错误状态
		fmt.Printf("[DEBUG] 下载被拒绝 - ID: %s, 原因: 并发下载数已达上限 (%d)，保持就绪状态\n", mediaInfo.Id, globalConfig.DownNumber)
		// 不发送错误状态，保持就绪状态，让前端处理队列
		// r.progressEventsEmit(mediaInfo, "下载被拒绝：并发下载数已达上限", shared.DownloadStatusError)
	}
}

func (r *Resource) parseHeaders(mediaInfo MediaInfo) (map[string]string, error) {
	headers := make(map[string]string)

	if hh, ok := mediaInfo.OtherData["headers"]; ok {
		var tempHeaders map[string][]string
		if err := json.Unmarshal([]byte(hh), &tempHeaders); err != nil {
			return headers, fmt.Errorf("parse headers JSON err: %v", err)
		}

		for key, values := range tempHeaders {
			if len(values) > 0 {
				headers[key] = values[0]
			}
		}
	}

	return headers, nil
}

func (r *Resource) wxFileDecode(mediaInfo MediaInfo, fileName, decodeStr string) (string, error) {
	sourceFile, err := os.Open(fileName)
	if err != nil {
		return "", err
	}
	defer sourceFile.Close()
	mediaInfo.SavePath = strings.ReplaceAll(fileName, ".mp4", "_decrypt.mp4")

	destinationFile, err := os.Create(mediaInfo.SavePath)
	if err != nil {
		return "", err
	}
	defer destinationFile.Close()

	_, err = io.Copy(destinationFile, sourceFile)
	if err != nil {
		return "", err
	}
	err = r.decodeWxFile(mediaInfo.SavePath, decodeStr)
	if err != nil {
		return "", err
	}
	return mediaInfo.SavePath, nil
}

func (r *Resource) progressEventsEmit(mediaInfo MediaInfo, args ...string) {
	Status := shared.DownloadStatusError
	Message := "ok"

	if len(args) > 0 {
		Message = args[0]
	}
	if len(args) > 1 {
		Status = args[1]
	}

	// 当下载完成时，Message 包含完整的保存路径
	savePath := mediaInfo.SavePath
	if Status == shared.DownloadStatusDone {
		savePath = Message
	}

	httpServerOnce.send("downloadProgress", map[string]interface{}{
		"Id":       mediaInfo.Id,
		"Status":   Status,
		"SavePath": savePath,
		"Message":  Message,
	})
	return
}

func (r *Resource) decodeWxFile(fileName, decodeStr string) error {
	decodedBytes, err := base64.StdEncoding.DecodeString(decodeStr)
	if err != nil {
		return err
	}
	file, err := os.OpenFile(fileName, os.O_RDWR, 0644)
	if err != nil {
		return err
	}
	defer file.Close()

	byteCount := len(decodedBytes)
	fileBytes := make([]byte, byteCount)
	n, err := file.Read(fileBytes)
	if err != nil && err != io.EOF {
		return err
	}

	if n < byteCount {
		byteCount = n
	}

	xorResult := make([]byte, byteCount)
	for i := 0; i < byteCount; i++ {
		xorResult[i] = decodedBytes[i] ^ fileBytes[i]
	}
	_, err = file.Seek(0, 0)
	if err != nil {
		return err
	}

	_, err = file.Write(xorResult)
	if err != nil {
		return err
	}
	return nil
}
